// KyPhoneUsbDrv.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
#include "KyPhoneHidDrv.h"

#define EXP_FUN KYPHONEHIDDRV_API

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include "UsbIo.h"
#include "Qunue.h"

#include <dbt.h>

#include <stdlib.h>
#include <stdio.h>
#include "setupapi.h"
#include "..\protocol\wjprotocol.h"

extern HWND g_hChildWnd;

#define     DEFALT_DEV                      ((HANDLE)(-3))
#define     BROADCAST_HANDLE                ((HANDLE)(-2))
void fmtPrintln(void* buf, int len);

/* Low Level Device Interface*/
/*****************************************************
*  Read function, 
*****************************************************/
DWORD  WINAPI thread_read_s1629(LPVOID lpThreadParameter )
{
    BYTE lastidx = 0xFF;
    MC_DEVICES * pDev = (MC_DEVICES *)lpThreadParameter;
	if( pDev == NULL ) return 0;

	pDev->bTaskRun = 1;

    HANDLE hWaitObject[3] ;
    hWaitObject[0] = pDev->OvRd.hEvent;
    hWaitObject[1] = g_hUsbDevMap.hEVTUsbExit;
    hWaitObject[2] = pDev->hEvtDemount;
    DWORD tick0 = GetTickCount();

    while(1)
    {   
        BYTE buff[10];
        DWORD TransBytes = 0;
        DWORD ticks = GetTickCount();
        MyTrace("Read ticks %d\n", ticks - tick0);
   
        memset(buff, 0xff, 5);
        if(!ReadFile(pDev->hRead, buff, 5, &TransBytes, &pDev->OvRd))
        {
            DWORD error = GetLastError();
            if(error == ERROR_IO_PENDING)
            {

                DWORD dwEventid = WaitForMultipleObjects(3, hWaitObject, FALSE, INFINITE );
                if( dwEventid == WAIT_OBJECT_0 )
                {
                    if(!GetOverlappedResult(pDev->hRead, &pDev->OvRd, &TransBytes, TRUE))
                    {
                        break;
                    }
                    error = GetLastError();
                    if(error == ERROR_DEVICE_NOT_CONNECTED)
                    {
                        break;
                    }               
                }
                if( dwEventid >= WAIT_OBJECT_0 + 1 )
                {
                    break;
                }
            }
        }
        tick0 = GetTickCount64();
        if (tick0 - ticks > 200) lastidx = 0xFF;

        DWORD dwEventid = WaitForMultipleObjects(2, &hWaitObject[1], FALSE, 0);
        if( dwEventid == WAIT_OBJECT_0 || dwEventid == (WAIT_OBJECT_0+1) )
        {
            break;
        }

        if( TransBytes )
        {//Notice :
            //buff[0] -->Usb Point number
            //buff[1] --> bit7 = buff[4]:bit0 !!! use one bit of last byte to indentify data freshed.
            //buff[2/3] -->Transfer data
            //buf[4] --> bit7:1 transfer data, bit0 : auto revert each HID package.So host can indentify all data in HID register are updated.
            BYTE swap = (buff[1] & 0x80) ? 1 : 0;
            BYTE idx = (buff[4] & 1);
            buff[4] = (buff[4] & 0xFE) | swap;
            INT len = 3;
            fmtPrintln(&buff[1], 4);
            if (lastidx == idx) {
                MyTrace("===?? idx not changed ??==\n");
                //fmtPrintln(&buff[1], 4);
                continue;
            }
            lastidx = idx;
            while (len>1) {
                if (buff[len + 1] == 0xFF)
                    len--;
                else
                    break;
            }
            if (len) {
                if (0 && buff[2] == 0xFF) {
                    BYTE testc[] = { 0xFF, 0xFF, 0x01,  0xE5,  0xFF, 0xFF, 0xFF, 0x0F, 0xD1, 0x01, 0x18, 0x09, 0x09, 0x09, 0x0A, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xF0, 0xED };
                    PostToQunue(pDev->hInBuff, testc, sizeof(testc));
                }
                
                PostToQunue(pDev->hInBuff, &buff[2], 3);
                char strlog[128] ="";
                for (int i = 2; i < 5; i++) {
                    char str[16];
                    sprintf_s(str, "%02X,", buff[i]);
                    strcat(strlog, str);
                }
                MyTrace("Data in %s", strlog);
                //g_hUsbDevMap.pCallbackDec(GetHandle(pDev));
                if(g_hChildWnd && IsWindow(g_hChildWnd))
                    PostMessage(g_hChildWnd, WM_HID_DATAIN, (WPARAM)GetHandle(pDev), 3);
            }
            continue;
        }
        else
        {
            SuspecDevicePlugOut();
            Sleep(100);
        }

    }
    CancelIo(pDev->hRead);
	pDev->bTaskRun = 0;
    MyTrace(">>>>>> Usb Read Thead (m99) End!");
    return 0;
}

static BOOL read_device(HANDLE hCom, USHORT InputReportLen, BYTE* InputReport)
{
    memset( InputReport, 0, InputReportLen);
    bool found =false;
    DWORD TransBytes;
    
    //-------------------------------
    return ReadFile( hCom, InputReport, InputReportLen, &TransBytes, NULL);
}


/*****************************************************
*  Write function,  IOCTL_USB_GET_NODE_CONNECTION_INFORMATION 
*****************************************************/
static BOOL write_device_s1629(HANDLE hDevice, USHORT OutputReportLen,BYTE *Output)
{
    MC_DEVICES * pDev = (MC_DEVICES*)hDevice;   
    BYTE OutputReport[255] = {0,0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; //new BYTE[OutputReportLen+15];
    bool found =false;
    DWORD TransBytes;
    OutputReport[0] = 00;
    OutputReport[1] = 0x80; (BYTE)OutputReportLen;
    memcpy(&OutputReport[2], (BYTE *)Output, OutputReportLen);
    
    if( !WriteFile( pDev->hWrite, OutputReport, 5, &TransBytes, &pDev->OvWr))
    {
        if(GetLastError() == ERROR_IO_PENDING)
        {
            HANDLE hWaitObject[2] ;
            hWaitObject[0] = pDev->OvWr.hEvent;
            hWaitObject[1] = g_hUsbDevMap.hEVTUsbExit;
            DWORD dwEventid = WaitForMultipleObjects(2, hWaitObject, FALSE, INFINITE );
            if( dwEventid == WAIT_OBJECT_0 )
            {
                if(!GetOverlappedResult(pDev->hWrite, &pDev->OvWr, &TransBytes, TRUE))
                {
                    return false;
                }
                if( GetLastError() == ERROR_DEVICE_NOT_CONNECTED )
                {
                    return false;
                }               
            }
            if( dwEventid == WAIT_OBJECT_0 + 1 )
            {
                return false;
            }            
        }
    }
    return TRUE;
}
/////////////////////////////////////////////////////////////////////////

INT ReadUSBDev_s1629(HANDLE hDevice, void * pbuf, int dwSize,\
               int timeout,DWORD * pErr)
{
    //return (INT)read_device(HANDLE hCom, USHORT InputReportLen)
    MC_DEVICES * pDev = GetUsbDviceHandle(hDevice); 

    BYTE * ptr = (BYTE *)pbuf;


    if( pDev == NULL ){ Sleep(timeout);  return 0;}
    int len; 
    do{
        len = GetQunueUsed(pDev->hInBuff);
        if( len )
        {
            if (len > 3) {
                MyTrace("wrong len %d\n", len);
            }
            if( dwSize > len ) dwSize = len;
            ::PeekFromQunue( pDev->hInBuff,ptr,dwSize);
            break;
        }
        Sleep(10);
        timeout -= 10;
    }while( timeout < 0);


    return len;
}


INT WriteUSBDev_s1629(HANDLE hDevice , void* pvbuf, int dwSize, DWORD * err)
{
    //Phrase the package and send diffrent package at diffrent output time
    BYTE* pbuf = (BYTE* )pvbuf;
    int nWriteLen = dwSize;
    MC_DEVICES * pDev = GetUsbDviceHandle(hDevice);
    
    while(pDev != NULL )
    {
        BYTE * psrc = (BYTE *)pbuf;

		if( pvbuf )
		{
			char sdbug[256]= "USB-W:";
			for(int i=0; i<dwSize; i++)
			{
				char stmp[6];
				sprintf(stmp, " %02X",*((BYTE*)pvbuf + i));
				strcat(sdbug, stmp);
			}
            strcat(sdbug, "\n");
			OutputDebugString(sdbug);
		}

        while(nWriteLen)
        {
           DWORD ticks = GetTickCount();
           int diff = (int)(ticks - pDev->usbBlock);

            if(diff < 32 && pDev->usbBlock )
            {
                DelayUs((32-diff+1)*1000);
            }
            pDev->usbBlock = GetTickCount();
            int len = nWriteLen > 3 ? 3 : nWriteLen;
            if( FALSE == write_device_s1629(pDev, len, (BYTE *)pbuf) )
                break;
            pbuf += len;
            nWriteLen -= len;
            
        }

		
        
        if( hDevice != BROADCAST_HANDLE ) 
            return dwSize-nWriteLen;
        
        pDev = GetUsbDviceHandle(pDev);
        pbuf = (BYTE* )pvbuf;
        nWriteLen = dwSize ;
    }
    return dwSize;
}



const HID_DRIVER drv_sss1629 = {
    CHIP_SSS1629,
    12,
    0,
    G_PID_1629_TXJ,
    G_VID_SSS,
    thread_read_s1629,
    ReadUSBDev_s1629,
    WriteUSBDev_s1629,
};



//gnd  2   3  vbus
//GND D+  D-  VBUS


//VBUS D+ D-